package com.serie402.web.action;

import java.util.ArrayList;
import java.util.Calendar;

import org.apache.log4j.Logger;

import com.kiss.fw.action.AbstractAction;
import com.kiss.fw.context.ActionContext;
import com.kiss.fw.exceptions.ActionException;
import com.kiss.fw.utils.Util;
import com.kiss.fw.utils.cache.TimedCache;
import com.serie402.common.bo.Author;
import com.serie402.common.bo.News;
import com.serie402.common.bo.Photo;
import com.serie402.common.bo.PhotoAlbum;
import com.serie402.common.delegate.NewsDelegate;
import com.serie402.common.dto.NewsDTO;
import com.serie402.common.dto.page.NewsPageDTO;
import com.serie402.common.utils.Constants;

public final class NewsAction extends AbstractAction {
	private static final Logger logger = Logger.getLogger(NewsAction.class);
	private static TimedCache<String, NewsPageDTO> newsPageCache = null;
	
	public NewsAction() {
		int size = Util.parseInt(Util.getProperty(Constants.Property.CACHE_SIZE_NEWS_PAGE), 30);
		int timeout = Util.parseInt(Util.getProperty(Constants.Property.CACHE_TIMEOUT_NEWS_PAGE), 5);
		
		newsPageCache = new TimedCache<String, NewsPageDTO>(size, timeout);
	}
	
	/**
	 * Validate action request.
	 * 
	 * @param ActionContext _context
	 */
	@Override
	public boolean validate(final ActionContext _context) {
		boolean returnVal = true;
		
		if(_context.isCreateAction()) {
			final String title = _context.getRequest().getParameter("title");
			final String description = _context.getRequest().getParameter("description");
			final String date = _context.getRequest().getParameter("date");
			final String importance = _context.getRequest().getParameter("importance");
			final String category = _context.getRequest().getParameter("category");
			final String subCategory = _context.getRequest().getParameter("subCategory");
			final String authorId = _context.getRequest().getParameter("authorId");
			final String newsContent = _context.getRequest().getParameter("content");
			
			// NOT REQUIRED: albumId & photoId
			if(Util.isStringEmpty(title) || Util.isStringEmpty(description) || Util.isStringEmpty(date) || Util.isStringEmpty(importance) || Util.isStringEmpty(category) || Util.isStringEmpty(subCategory) || Util.isStringEmpty(authorId) || Util.isStringEmpty(newsContent)) {
				returnVal = false;
			}
			
			if(returnVal) {
				if(!isValidInput(category, Constants.Property.INPUT_VALIDATION_NEWS_CATEGORY)) {
					returnVal = false;
				}
				
				if(!isValidInput(subCategory, Constants.Property.INPUT_VALIDATION_NEWS_SUB_CATEGORY)) {
					returnVal = false;
				}
			}
		}
		else if(_context.isReadAction()) {
			String category = _context.getRequest().getParameter(Constants.Navigation.CATEGORY);
			String subCategory = _context.getRequest().getParameter(Constants.Navigation.SUB_CATEGORY);
			
			if(!Util.isStringEmpty(category)) {
				if(!isValidInput(category, Constants.Property.INPUT_VALIDATION_NEWS_CATEGORY)) {
					returnVal = false;
				}
			}
			
			if(!Util.isStringEmpty(subCategory)) {
				if(!isValidInput(subCategory, Constants.Property.INPUT_VALIDATION_NEWS_SUB_CATEGORY)) {
					returnVal = false;
				}
			}
		}
		else if(_context.isUpdateAction()) {
			returnVal = false;
		}
		else if(_context.isDeleteAction()) {
			returnVal = false;
		}
		else if(_context.isSearchAction()) {
			returnVal = false;
		}
		
		return returnVal;
	}
	
	public void create(ActionContext _context) throws ActionException {
		NewsPageDTO pageDto = null;
		
		try {
			NewsDelegate.create(generateNewsDTO(_context));
		}
		catch(Exception _exception) {
			handleActionException(logger, "update", _exception);
		}
		
		_context.setRequestAttribute(Constants.Mappings.NEWS_DTO, pageDto);
	}
	
	public void read(ActionContext _context) throws ActionException {
		NewsDTO dto = generateNewsDTO(_context);
		NewsPageDTO pageDto = null;
		
		try {
			String cacheKey = generateCacheKey(dto);
			pageDto = newsPageCache.get(cacheKey);
			
			synchronized(newsPageCache) {
				if(pageDto == null) {
					// retrieving news
					NewsDelegate.read(dto);
					
					// set dto
					pageDto = generateNewsPageDTO(dto);
					
					// update cache
					newsPageCache.put(cacheKey, pageDto);
				}
			}
		}
		catch(Exception _exception) {
			handleActionException(logger, "update", _exception);
		}
		
		_context.setRequestAttribute(Constants.Mappings.NEWS_DTO, pageDto);
	}
	
	public void update(ActionContext _context) throws ActionException {
		NewsPageDTO pageDto = null;
		
		try {
			NewsDelegate.update(generateNewsDTO(_context));
		}
		catch(Exception _exception) {
			handleActionException(logger, "update", _exception);
		}
		
		_context.setRequestAttribute(Constants.Mappings.NEWS_DTO, pageDto);
	}
	
	public void delete(ActionContext _context) throws ActionException {
		NewsPageDTO pageDto = null;
		
		try {
			NewsDelegate.delete(generateNewsDTO(_context));
		}
		catch(Exception _exception) {
			handleActionException(logger, "update", _exception);
		}
		
		_context.setRequestAttribute(Constants.Mappings.NEWS_DTO, pageDto);
	}
	
	public void search(ActionContext _context) throws ActionException {
		NewsPageDTO pageDto = null;
		
		try {
			NewsDelegate.search(generateNewsDTO(_context));
		}
		catch(Exception _exception) {
			handleActionException(logger, "update", _exception);
		}
		
		_context.setRequestAttribute(Constants.Mappings.NEWS_DTO, pageDto);
	}
	
	public void browse(ActionContext _context) throws ActionException {
	}
	
	private static String generateCacheKey(NewsDTO _dto) {
		StringBuffer returnVal = new StringBuffer();
		
		if(!Util.isStringEmpty(_dto.getNews().getCategory())) {
			returnVal.append(_dto.getNews().getCategory());
			
			if(!Util.isStringEmpty(_dto.getNews().getSubCategory())) {
				returnVal.append(":");
				returnVal.append(_dto.getNews().getSubCategory());
			}
		}
		else {
			returnVal.append("all");
		}
		
		return returnVal.toString();
	}
	
	private static NewsPageDTO generateNewsPageDTO(final NewsDTO _dto) {
		StringBuffer titleKey = new StringBuffer("webpage.news");
		
		if(!Util.isStringEmpty(_dto.getNews().getCategory())) {
			titleKey.append('.');
			titleKey.append(_dto.getNews().getCategory());
			
			if(!Util.isStringEmpty(_dto.getNews().getSubCategory())) {
				titleKey.append('.');
				titleKey.append(_dto.getNews().getSubCategory());
			}
		}
		
		NewsPageDTO returnVal = new NewsPageDTO();
		
		returnVal.setTopNews(new ArrayList<News>(3));
		returnVal.setMidLeftNews(new ArrayList<News>(5));
		returnVal.setMidRightNews(new ArrayList<News>(10));
		returnVal.setBottomNews(new ArrayList<News>(6));
		returnVal.setPageTitle(Util.getProperty(titleKey.toString()));
		returnVal.setWindowTitle(Util.getProperty(titleKey.toString()));
		
		for(int i=0; i < _dto.getNewsList().size(); i++) {
			News tempNews = _dto.getNewsList().get(i);
			
			// news already comes sorted so there is no
			// need to check the importance
			if(returnVal.getTopNews().size() < 3) {
				returnVal.getTopNews().add(tempNews);
			}
			else if(returnVal.getMidCenterNews() == null) {
				returnVal.setMidCenterNews(tempNews);
			}
			else if(returnVal.getMidLeftNews().size() < 5) {
				returnVal.getMidLeftNews().add(tempNews);
			}
			else if(returnVal.getMidRightNews().size() < 10) {
				returnVal.getMidRightNews().add(tempNews);
			}
			else if(returnVal.getBottomNews().size() < 6) {
				returnVal.getBottomNews().add(tempNews);
			}
		}
		
		return returnVal;
	}
	
	/**
	 * Generates the DTO used for the Delegate.
	 * 
	 * @param ActionContext _context
	 * @return NewsDTO
	 */
	private static NewsDTO generateNewsDTO(final ActionContext _context) {
		NewsDTO dto = new NewsDTO();
		
		if(_context.isCreateAction()) {
			dto = new NewsDTO(generateNews(_context));
		}
		else if(_context.isReadAction()) {
			News news = new News();
			news.setCategory(_context.getRequest().getParameter("category"));
			news.setSubCategory(_context.getRequest().getParameter("subCategory"));
			
			dto.setNews(news);
		}
		else if(_context.isUpdateAction()) {
			dto = new NewsDTO(generateNews(_context));
		}
		else if(_context.isDeleteAction()) {
			dto = new NewsDTO(Util.parseInt(_context.getRequest().getParameter("newsId"), -1));
		}
		else if(_context.isSearchAction()) {
			dto = new NewsDTO(generateNews(_context));
		}
		
		return dto;
	}
	
	/**
	 * Retrieves a News object that is populated via the details in the form.
	 * 
	 * @param ActionContext _context
	 * @return News
	 */
	private static News generateNews(final ActionContext _context) {
		// TODO: Implement Images for News
		Calendar date = Calendar.getInstance();
		
		if(_context.getRequest().getParameter("useCurrentDate").equals("false")) {
			int month = Util.parseInt(_context.getRequest().getParameter("month"), date.get(Calendar.MONTH));
			int day = Util.parseInt(_context.getRequest().getParameter("day"), date.get(Calendar.DATE));
			int year = Util.parseInt(_context.getRequest().getParameter("year"), date.get(Calendar.YEAR));
			
			date.set(year, month, day);
		}
		
		News news = new News();
		news.setAuthor(new Author(Util.parseInt(_context.getRequest().getParameter("authorId"), -1), null));
		news.setImportance(Util.parseInt(_context.getRequest().getParameter("importance"), -1));
		news.setCategory(_context.getRequest().getParameter("category"));
		news.setSubCategory(_context.getRequest().getParameter("subCategory"));
		news.setDescription(_context.getRequest().getParameter("description"));
		news.setContent(_context.getRequest().getParameter("content"));
		news.setPhotoAlbum(new PhotoAlbum());
		news.getPhotoAlbum().setAlbumId(Util.parseInt(_context.getRequest().getParameter("albumId"), -1));
		news.setPhoto(new Photo(Util.parseInt(_context.getRequest().getParameter("photoId"), 0), Util.parseInt(_context.getRequest().getParameter("albumId"), -1), null, null));
		news.setDate(date);
		
		return news;
	}
}